package com.baofu.paycore.service.processor.transfer;

import com.baofu.clear.service.facade.enums.EventTypeEnum;
import com.baofu.paycore.biz.external.clear.EventService;
import com.baofu.paycore.biz.external.clear.model.EventRuleResBO;
import com.baofu.paycore.common.enums.FlagEnum;
import com.baofu.paycore.common.enums.FundTypeEnum;
import com.baofu.paycore.common.exception.ManagerErrorCode;
import com.baofu.paycore.common.utils.Constant;
import com.baofu.paycore.dal.model.SubTransferDO;
import com.baofu.paycore.manager.model.TransferBO;
import com.baofu.paycore.service.facade.enums.PayCoreErrorCode;
import com.baofu.paycore.service.facade.enums.PayStatusEnums;
import com.baofu.paycore.service.facade.model.transfer.TransferDTO;
import com.baofu.paycore.service.facade.model.transfer.TransferFundDTO;
import com.baofu.paycore.service.processor.PayBaseProcessor;
import com.google.common.collect.Lists;
import com.system.commons.exception.BizServiceException;
import com.system.commons.sequence.redis.SequenceFacade;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * 转账资金单处理类
 *
 * <p/>
 *      1、构建支付属性
 * </p>
 * User: LZQ Date: 2016/04/20  Version: 1.0
 */
@Slf4j
@Component
public class TransferFundProcessor implements PayBaseProcessor<TransferBO, TransferDTO> {

    /**
     * 资金单明细NO
     */
    @Autowired
    private SequenceFacade sequenceFacade;

    /**
     * 会计事件服务
     */
    @Autowired
    private EventService eventService;

    /**
     * 构建支付属性
     *
     * <p>
     * 转账交易增加订单收费标识flagEnum， 用来标识这笔转账单是普通转账，还是收费交易单（如异步收取手续费交易）。
     * 同时，只有当订单是普通转账交易时， 才会去判断是否收费，若是收费交易单，无需判断订单的业务收费金额。
     * </p>
     *
     * @param transferBO      支付模型
     * @param transferDTO     请求参数
     */
    @Override
    public PayBaseProcessor process(TransferBO transferBO, TransferDTO transferDTO) {
        //手续费
        if (FlagEnum.FALSE.getCode().equals(transferDTO.getFeeFlag()) &&
                Constant.validateLong(transferDTO.getBizChargeAmt()) > 0){
            if(transferDTO.getTransferOutDTO() == null){
                throw new BizServiceException(ManagerErrorCode.TRANSFEROUT_PARAM_IS_NULL);
            }
            processByFee(transferBO, transferDTO);
            return this;
        }
        //无手续费
        processByNoFee(transferBO, transferDTO);
        return this;
    }

    /**
     * 转账有手续费处理
     *
     * @param transferBO        转账BO对象
     * @param transferDTO       转账DTO对象
     */
    private void processByFee(TransferBO transferBO, TransferDTO transferDTO){
        List<SubTransferDO> subTransferDOs = new ArrayList<>();
        eventProcess(transferDTO);
        long amt = transferDTO.getAmt() - Constant.validateLong(transferDTO.getBizChargeAmt());
        //获取冻结单
        SubTransferDO freezeFund = this.getSubTransfer(transferBO.getPayNo(), transferDTO.getTransferOutDTO(),
                transferDTO.getAmt(),transferDTO.getTransferOutDTO().getAccountNo(), transferDTO.getOperator(),
                transferDTO.getCcy());
        freezeFund.setFundType(FundTypeEnum.TRANSFER_FREEZE.getCode());
        //解冻转账单
        SubTransferDO unfreezeFund = this.getSubTransfer(transferBO.getPayNo(), transferDTO.getTransferOutDTO(),
                amt,transferDTO.getTransferOutDTO().getAccountNo(),
                transferDTO.getOperator(), transferDTO.getCcy());
        unfreezeFund.setEventNo(transferDTO.getEventNo());
        unfreezeFund.setFundType(FundTypeEnum.UNFREEZE_TRANSFER.getCode());
        if(transferDTO.getTransferInDTO() != null){
            unfreezeFund.setInAccountNo(transferDTO.getTransferInDTO().getAccountNo());
            unfreezeFund.setInContractNo(transferDTO.getTransferInDTO().getContractNo());
        }
        if(transferDTO.getTransferOutDTO() != null){
            unfreezeFund.setOutAccountNo(transferDTO.getTransferOutDTO().getAccountNo());
            unfreezeFund.setOutContractNo(transferDTO.getTransferOutDTO().getContractNo());
        }
        //解冻转账手续费单
        if (transferDTO.getTransferOutDTO() != null && Constant.validateLong(transferDTO.getBizChargeAmt()) >0){
            SubTransferDO subTransferDOByFee =
                    this.getSubTransfer(transferBO.getPayNo(), transferDTO.getTransferOutDTO(),
                            Constant.validateLong(transferDTO.getBizChargeAmt()),
                            transferDTO.getTransferOutDTO().getAccountNo(), transferDTO.getOperator(),
                            transferDTO.getCcy());
            subTransferDOByFee.setEventNo(getEventNo(EventTypeEnum.FEE, transferDTO.getSubBizType()));
            subTransferDOByFee.setFundType(FundTypeEnum.FEE.getCode());
            subTransferDOs.add(subTransferDOByFee);
        }
        subTransferDOs.add(freezeFund);
        subTransferDOs.add(unfreezeFund);
        transferBO.setSubTransferDO(subTransferDOs);
    }
    /**
     * 获取手续费资金单
     *
     * @param transferFundDTO   转账资金单
     * @return                  子资金单
     */
    private SubTransferDO getSubTransfer(String payNo, TransferFundDTO transferFundDTO, long payAmount,
                                         String outAccountNo, String operator, String ccy){
        SubTransferDO subTransferDO = new SubTransferDO();
        subTransferDO.setPayNo(payNo);
        subTransferDO.setFundDetailNo(sequenceFacade.getUniqueSeq());
        subTransferDO.setStatus(PayStatusEnums.INIT.getCode());
        subTransferDO.setPayAmount(payAmount);
        subTransferDO.setCcy(ccy);
        subTransferDO.setOutAccountNo(outAccountNo);
        subTransferDO.setOutContractNo(transferFundDTO.getContractNo());
        subTransferDO.setFreezeNo(sequenceFacade.getUniqueSeq());
        subTransferDO.setCreatedBy(operator);
        subTransferDO.setUpdatedBy(operator);

        return subTransferDO;
    }

    /**
     * 会计事件处理流程
     *
     * @param transferDTO         转账订单
     */
    private void eventProcess(TransferDTO transferDTO) {

        //出款方入款方,一方为空需查会计事件
        if (transferDTO.getTransferOutDTO() == null
                || StringUtils.isEmpty(transferDTO.getTransferOutDTO().getAccountNo())
                || transferDTO.getTransferInDTO() == null
                || StringUtils.isEmpty(transferDTO.getTransferInDTO().getAccountNo())) {

            if(FlagEnum.TRUE.getCode().equals(transferDTO.getFeeFlag())) {
                transferDTO.setEventNo(getEventNo(EventTypeEnum.FEE, transferDTO.getSubBizType()));
                return;
            }
            transferDTO.setEventNo(getEventNo(EventTypeEnum.PRODUCT, transferDTO.getSubBizType()));
        }
    }

    /**
     * 获取会计事件号
     *
     * @param eventType     事件类型
     * @param subBizType    产品细类
     * @return              会计事件号
     */
    private String getEventNo(EventTypeEnum eventType, String subBizType){
        EventRuleResBO eventRuleResBO = eventService.queryEventNo(eventType, subBizType);

        if (!PayStatusEnums.SUCCESS.getCode().equals(eventRuleResBO.getStatus())) {
            log.error("会计事件获取失败,事件类型:{},{}",eventType,subBizType);
            throw new BizServiceException(PayCoreErrorCode.EVENT_NO_NOT_EXIST);
        }
        return eventRuleResBO.getEventNo();
    }

    /**
     * 转账无手续费处理
     *
     * @param transferBO      转账BO对象
     * @param transferDTO     转账DTO对象
     */
    private void processByNoFee(TransferBO transferBO, TransferDTO transferDTO){

        eventProcess(transferDTO);
        transferBO.setEventNo(transferDTO.getEventNo());
        SubTransferDO subTransferDO = new SubTransferDO();

        subTransferDO.setPayNo(transferBO.getPayNo());
        subTransferDO.setStatus(PayStatusEnums.INIT.getCode());
        subTransferDO.setFundDetailNo(sequenceFacade.getUniqueSeq());
        subTransferDO.setPayAmount(transferDTO.getAmt());
        subTransferDO.setCcy(transferDTO.getCcy());
        subTransferDO.setEventNo(transferDTO.getEventNo());
        subTransferDO.setFundType(FundTypeEnum.TRANSFER.getCode());
        subTransferDO.setCreatedBy(transferDTO.getOperator());
        subTransferDO.setUpdatedBy(transferDTO.getOperator());
        if(transferDTO.getTransferInDTO() != null){
            subTransferDO.setInAccountNo(transferDTO.getTransferInDTO().getAccountNo());
            subTransferDO.setInContractNo(transferDTO.getTransferInDTO().getContractNo());
        }
        if(transferDTO.getTransferOutDTO() != null){
            subTransferDO.setOutAccountNo(transferDTO.getTransferOutDTO().getAccountNo());
            subTransferDO.setOutContractNo(transferDTO.getTransferOutDTO().getContractNo());
        }

        transferBO.setSubTransferDO(Lists.newArrayList(subTransferDO));
    }
}
